package medOffice;

import java.sql.SQLException;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import medOffice.dao.MedicoDAO;
import medOffice.dao.PacienteDAO;
import medOffice.dao.PlanoDAO;
import medOffice.dao.RepresentanteDAO;

/**
 * Classe que inicializa a clinica.
 * @author Tiago Leite - tiagohsl@lcc.ufcg.edu.br
 * @version 1.0 </br> 03/12/09
 *
 */
public class Clinica {	
	
	private String nomeDaClinica, telefone, endereco;
	private Agenda agenda;
	protected PacienteDAO daoPaciente;
	protected RepresentanteDAO daoRepresentante;
	protected MedicoDAO daoMedico;
	protected PlanoDAO daoPlano;

	/**
	 * Construtor da Clinica. (Inicializa o BD)
	 * 
	 * @param String nome da clinica
	 * @throws Exception 
	 * 				lancada caso o nome da clinica seja invalido.
	 */
	public Clinica(String nome) throws Exception {
		setNomeDaClinica(nome);
		daoRepresentante = new RepresentanteDAO();
		daoPaciente = new PacienteDAO();
		daoMedico = new MedicoDAO();
		daoPlano = new PlanoDAO();
	}

	/**
	 * Metodo que adiciona um paciente a clinica.
	 * 
	 * @param Paciente paciente
	 * @return boolean True caso o paciente seja add com sucesso,
	 * false caso contrario.
	 * @throws SQLException
	 */
	public boolean addPaciente(Paciente paciente) throws SQLException {
		if (paciente == null) {
			return false;
		}		
		if(getListaPacientes().contains(paciente)) {
			return false;
		}
		getDaoPaciente().create(paciente);
		return true;
		
	}

	/**
	 * Metodo que remove um paciente da clinica.
	 * 
	 * @param String nome do paciente
	 * @param String cpf do paciente
	 * @return boolean True caso o paciente seja excluido com sucesso,
	 * false caso contrario.
	 * @throws SQLException
	 */
	public boolean removePaciente(String nome, String cpf) throws SQLException {
		if (nome == null || cpf == null) {
			return false;
		}
		Paciente aDeletar = null;
		try {
			aDeletar = new Paciente(nome,cpf);
		} catch (Exception e) {
			return false;
		}
		if( getListaPacientes().contains(aDeletar)) {
			try{
				getAgenda().cancelaConsultaCPF(cpf);
				getDaoPaciente().delete(cpf);
				return true;
			}catch(Exception ex){
				ex.printStackTrace();
			}
		
		}
		return false;
	}

	/**
	 * Metodo que adiciona um representante a clinica.
	 * 
	 * @param Representante representante a ser add.
	 * @return boolean True caso o representante seja add com sucesso,
	 * false caso contrario.
	 * @throws Exception lancada caso de algum problema com o BD.
	 */
	public boolean addRepresentante(Representante representante)
			throws Exception {
		if (representante != null
				&& !getListaRepresentantes().contains(representante)) {
			getDaoRepresentante().create(representante);
			return true;
		}
		return false;
	}

	/**
	 * Metodo que remove um representante da clinica
	 * 
	 * @param String nome do representante
	 * @param Integer id do representante
	 * @return boolean True caso o representante seja removido com sucesso, 
	 * false caso contrario.
	 * @throws SQLException Lancada caso de algum problema com as dependencias
	 * do BD.
	 */
	public boolean removeRepresentante(String nome, int id) throws SQLException {
		Iterator<Representante> it = getListaRepresentantes().iterator();
		Representante representanteTemporario = null;

		while (it.hasNext()) {
			representanteTemporario = it.next();
			if (representanteTemporario.getNome().equals(nome)
					&& representanteTemporario.getId() == id) {
				getDaoRepresentante().delete(representanteTemporario.getId());
				return true;
			}
		}
		return false;
	}

	/**
	 * Metodo modificador que seta o nome da Clinica.
	 * 
	 * @param String nome da Clinica
	 * @throws Exception
	 *             Nome invalido (Numeros no nome da Clinica).
	 */
	public void setNomeDaClinica(String nomeDaClinica) throws Exception {
		if (!Verificador.verificaNome(nomeDaClinica)) {
			throw new Exception("Nome invalido");
		}
		this.nomeDaClinica = nomeDaClinica;
	}

	/**
	 * Metodo acessador que retorna o nome da clinica.
	 * 
	 * @return String nome da clinica
	 */
	public String getNomeDaClinica() {
		return nomeDaClinica;
	}

	/**
	 * Metodo acessador que retorna o telefone da clinica.
	 * 
	 * @return String telefone da clinica.
	 */
	public String getTelefone() {
		return telefone;
	}

	/**
	 * Metodo modificador que seta o telefone da clinica
	 * 
	 * @param String telefone da clinica
	 * @throws Exception
	 *             Telefone com caracteres invalidos (e. g. letras)
	 */
	public void setTelefone(String telefone) throws Exception {
		if (Verificador.verificaTelefone(telefone)) {
			this.telefone = telefone;
		} else {
			throw new Exception("Telefone com caracteres invalidos");
		}
	}

	/**
	 * Metodo acessador que retorna o endereco da Clinica
	 * 
	 * @return String endereco da clinica
	 */
	public String getEndereco() {
		return endereco;
	}

	/**
	 * Metodo modificador que seta o endereco da Clinica.
	 * 
	 * @param String endereco da clinica
	 * @throws Exception
	 *             Endereco invalido (nao segue a regra de enderecos).
	 */
	public void setEndereco(String endereco) throws Exception {
		if (Verificador.verificaEndereco(endereco)) {
			this.endereco = endereco;
		} else {
			throw new Exception("Endereco invalido");
		}
	}

	@Override
	public String toString() {
		return "Clinica: " + getNomeDaClinica() + "\nEndereco: "
				+ getEndereco() + "\nTelefone: " + getTelefone();
	}

	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof Clinica)) {
			return false;
		}
		Clinica outraClinica = (Clinica) obj;
		return outraClinica.getNomeDaClinica().equalsIgnoreCase(
				getNomeDaClinica());
	}

	/**
	 * Metodo que retorna a lista dos pacientes pelo nome.
	 * 
	 * @return List<Paciente> Pacientes ordenados por nome
	 * @throws SQLException 
	 */
	public List<Paciente> listaPacientesPorNome() throws SQLException {
		return sortPacientes(getListaPacientes());
	}

	/**
	 * Metodo que organiza uma lista de Pacientes pelo nome.
	 * 
	 * @param List<Paciente> lista de Pacientes
	 * @return List<Paciente> ordenada
	 */
	private List<Paciente> sortPacientes(List<Paciente> listaDePacientes) {
		Collections.sort(listaDePacientes, new Comparator<Object>() {
			public int compare(Object o1, Object o2) {
				Paciente c1 = (Paciente) o1;
				Paciente c2 = (Paciente) o2;
				return c1.getNome().compareTo(c2.getNome());
			}
		});
		return listaDePacientes;
	}

	/**
	 * Retorna o {@link Paciente} com o CPF especificado. Caso o paciente nao
	 * exista, sera retornado o valor nulo.
	 * 
	 * @param String
	 *            - CPF do paciente.
	 * @return Paciente
	 * @throws SQLException 
	 * @throws IllegalArgumentException
	 * 				lancada caso o cpf seja nulo.
	 */
	public Paciente findPaciente(String cpf) throws SQLException {
		if (cpf == null)
			throw new IllegalArgumentException("CPF nao pode ser nulo.");
		for (Paciente p : getListaPacientes()) {
			if (p.getCPF().equals(cpf))
				return p;
		}
		return null;
	}
	
	/**
	 * Metodo modificador que seta a agenda
	 * @param Agenda agenda
	 * @throws Exception 
	 * 				lancada caso a agenda passada seja nula.
	 */
	public void setAgenda(Agenda agenda) throws Exception {
		if (agenda == null)
			throw new Exception();
		this.agenda = agenda;
	}
	
	/**
	 * Metodo acessador que retorna uma Agenda
	 * @return Agenda
	 */
	public Agenda getAgenda() {
		return agenda;
	}
	
	/**
	 * Metodo acessador que retorna uma lista de pacientes no banco de dados 
	 * da clinica
	 * @return List<Paciente> pacientes da clinica.
	 * @throws SQLException
	 */
	public List<Paciente> getListaPacientes() throws SQLException {
		return daoPaciente.getListaPacientes();
	}

	/**
	 * Metodo acessador que retorna uma lista dos representantes no banco
	 * de dados da clinica
	 * 
	 * @return List<Representante> representantes da clinica.
	 * @throws SQLException
	 */
	public List<Representante> getListaRepresentantes() throws SQLException {
		return daoRepresentante.getListaRepresentantes();
	}
	
	/**
	 * Metodo acessador que retorna a lista de planos no banco de dados da 
	 * clinica
	 * @return List<PlanoDeSaude> lista de Planos de Saude
	 * @throws SQLException
	 */
	public List<PlanoDeSaude> getListaDePlanos() throws SQLException {
		return daoPlano.getListaPlanos();
	}
	
	/**
	 * Metodo que adiciona uma consulta ao banco de dados da clinica
	 * @param PlanoDeSaude plano desejado
	 * @return boolean True caso seja add com sucesso, False caso contrario
	 * @throws SQLException
	 */
	public boolean addPlanoDeSaude(PlanoDeSaude plano) throws SQLException {
		if (plano != null && !getListaDePlanos().contains(plano)) {
			getDaoPlano().create(plano);
			return true;
		}
		return false;
		
	}
	
	/**
	 * Metodo que remove um plano de saude do bando de dados da clinica.
	 * @param PlanoDeSaude plano
	 * @return boolean True caso seja removido com sucesso, false caso contrario.
	 * @throws SQLException
	 */
	public boolean removePlanoDeSaude(PlanoDeSaude plano) throws SQLException {
		if (plano != null && getListaDePlanos().contains(plano)){
			getDaoPlano().delete(plano.getCodigo());
			return true;
		}
		return false;
	}
	
	/**
	 * Metodo que gera um codigo para um plano de saude
	 * @return int codigo gerado
	 * @throws SQLException
	 */
	public int geraCodigoPlano() throws SQLException {
		return daoPlano.codigoMarcar();
	}
	
	/**
	 * Metodo que add um Medico ao banco de dados da clinica
	 * @param Medico medico
	 * @return boolean True caso ele seja add com sucesso, False
	 * caso contrario
	 * @throws SQLException
	 */
	public boolean addMedico(Medico medico) throws SQLException {
		if (medico != null && daoMedico.getMedico() == null) {
			daoMedico.create(medico);
			return true;
		}
		return false;
		
	}
	
	/**
	 * Metodo que limpa a tabela de plano de saude no BD da clinica.
	 * @throws SQLException
	 */
	public void deleteAllFromPlano() throws SQLException {
		getDaoPlano().deleteAll();
	}
	
	/**
	 * Metodo que limpa a tabela de paciente no BD da clinica.
	 * @throws SQLException
	 */
	public void deleteAllFromPaciente() throws SQLException {
		getDaoPaciente().deleteAll();
	}
	
	/**
	 * Metodo que edita os dados de um Representante na tabela
	 * @param Integer id do representante
	 * @param Representante desejado
	 * @throws SQLException 
	 * 			Caso nao consiga por algum motiva se conectar com o BD
	 */
	public void editaRepresentante(int id, Representante rep) throws SQLException{
		getDaoRepresentante().editaRepresentante(id, rep);
	}

	/**
	 * Metodo acessador que resgata a conexao do Paciente no BD.
	 * @return PacienteDAO do BD.
	 */
	public PacienteDAO getDaoPaciente() {
		return daoPaciente;
	}

	/**
	 * Metodo acessador que resgata a conexao do Representante no BD.
	 * @return RepresentanteDAO do BD.
	 */
	public RepresentanteDAO getDaoRepresentante() {
		return daoRepresentante;
	}
	
	/**
	 * Metodo acessador que resgata a conexao do Medico no BD.
	 * @return MedicoDAO do BD.
	 */
	public MedicoDAO getDaoMedico() {
		return daoMedico;
	}
	
	/**
	 * Metodo acessador que resgata a conexao do Plano De Saude no BD.
	 * @return PlanoDAO do BD.
	 */
	public PlanoDAO getDaoPlano() {
		return daoPlano;
	}
	
	

}
